package com.example.dingdong.websocketService;

import com.alibaba.fastjson.JSONObject;
import com.example.dingdong.websocketUtil.WebSocketConst;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * WebSocket 服务
 */
public class WebSocketService {

	private static final Logger log = LoggerFactory.getLogger(WebSocketService.class);

	// account-ipAddress(account-ipAddress) account关联ipAddress
	private static final ConcurrentHashMap<String, String> accountRelateIpAddress = new ConcurrentHashMap<>();

	// ipAddress-session(ipAddressId-会话) ipAddress值关联会话
	private static final ConcurrentHashMap<String, WebSocketSession> ipAddressRelateSession = new ConcurrentHashMap<>();

	// ipAddress-expiresTime(ipAddress-存活剩余时间) ipAddress值关联存活剩余时间
	private static final ConcurrentHashMap<String, Long> ipAddressRelateKeepAliveTime = new ConcurrentHashMap<>();

	/**
	 * 推送 Websocket 数据(单播模式)
	 * 
	 * @throws Exception void
	 */
	@Async
	public <T> void addJsonObjToSendUnicast(String type, T data, String ipAddress) throws Exception {
		// 1、封装数据
		JSONObject message = new JSONObject();
		message.put(WebSocketConst.TYPE, type);
		message.put(WebSocketConst.DATA, data);

		// 2、获取会话
		@SuppressWarnings("resource")
		WebSocketSession session = (ipAddress != null) ? ipAddressRelateSession.get(ipAddress) : null;
		if (session == null) {
			log.error("WS单播通信失败，对方没有在线，ipAddress：" + ipAddress);
			return;
		}

		// 3、单播通信
		synchronized (session) {
			session.sendMessage(new TextMessage(message.toJSONString().getBytes()));
			log.info("WS单播通信：ipAddress:" + ipAddress + ",发送数据:" + message.toJSONString());
		}
	}

	/**
	 * 推送 Websocket 数据(组播模式)
	 * 
	 * @throws Exception void
	 */
	@Async
	public <T> void addJsonObjToSendMulticast(String type, T data, List<String> ipAddressList) throws Exception {
		// 1、封装数据
		JSONObject message = new JSONObject();
		message.put(WebSocketConst.TYPE, type);
		message.put(WebSocketConst.DATA, data);

		// 2、组播通信
		for (int i = 0; i < ipAddressList.size(); i++) {
			String ipAddress = ipAddressList.get(i);
			@SuppressWarnings("resource")
			WebSocketSession session = (ipAddress != null) ? ipAddressRelateSession.get(ipAddress) : null;
			if (session == null) {
				log.error("WS组播通信失败，对方没有在线，ipAddress：" + ipAddress);
				continue;
			}

			synchronized (session) {
				session.sendMessage(new TextMessage(message.toJSONString().getBytes()));
				log.info("WS组播通信：ipAddress:" + ipAddress + ",message:" + message.toJSONString());
			}
		}
	}

	/**
	 * 推送 Websocket 数据(广播模式)
	 * 
	 * @throws Exception void
	 */
	@Async
	public <T> void addJsonObjToSendRadioBroadcast(String type, T data) throws Exception {
		// 1、封装数据
		JSONObject message = new JSONObject();
		message.put(WebSocketConst.TYPE, type);
		message.put(WebSocketConst.DATA, data);

		// 2、广播通信
		Iterator<Map.Entry<String, WebSocketSession>> iterator = ipAddressRelateSession.entrySet().iterator();
		while (iterator.hasNext()) {
			Map.Entry<String, WebSocketSession> entry = iterator.next();
			String ipAddress = entry.getKey();
			WebSocketSession session = entry.getValue();

			if (session == null) {
				log.error("WS广播通信失败，对方没有在线，ipAddress：" + ipAddress);
				continue;
			}

			synchronized (session) {
				session.sendMessage(new TextMessage(message.toJSONString().getBytes()));
				log.info("WS广播通信：ipAddress:" + ipAddress + ",message:" + message.toJSONString());
			}
		}
	}

	/**
	 * 心跳发送
	 * 
	 * @throws Exception
	 */
	public void addJsonObjHeartToSend(WebSocketSession session) throws Exception {
		if (session == null) {
			log.error("无法发送心跳，会话被销毁!");
			return;
		}

		// 1、组装数据
		JSONObject message = new JSONObject();
		message.put(WebSocketConst.TYPE, WebSocketConst.HEART);

		// 2、心跳发送
		synchronized (session) {
			session.sendMessage(new TextMessage(message.toJSONString().getBytes()));
			String ipAddress = session.getRemoteAddress().getHostString();
			log.info("心跳发送：ipAddress:" + ipAddress + ",message:" + message.toJSONString());
		}
	}

	public ConcurrentHashMap<String, WebSocketSession> getSessions() {
		return ipAddressRelateSession;
	}

	public ConcurrentHashMap<String, Long> getIpAddressRelateKeepAliveTime() {
		return ipAddressRelateKeepAliveTime;
	}

	public ConcurrentHashMap<String, String> getAccountrelateIpAddress() {
		return accountRelateIpAddress;
	}

}
